home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
uupc11yt.zip
/
RNEWS
/
RNEWS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-17
|
48KB
|
1,369 lines
/*--------------------------------------------------------------------*/
/* r n e w s . c */
/* */
/* Receive incoming news into the news directory. */
/* */
/* Written by Mike Lipsie; modified for UUPC/extended 1.11s by */
/* Andrew H., Derbyshire. */
/* */
/* Changes and Compilation Copyright (c) 1992 by Andrew H. */
/* Derbyshire. All rights reserved except as granted by the */
/* general UUPC/extended license. */
/* */
/* This package has been substantially modified. It will now */
/* copy compressed articles (assumed batches but they could be */
/* single articles) to the CMPRSSED directory and it will */
/* unbatch (if necessary) and deliver articles to their */
/* appropriate newsgroup directories. At the end, if the file */
/* was compressed it will invoke a batch file which will */
/* uncompress the file and then feed it back to rnews. */
/* */
/* Appropriate is defined as */
/* */
/* (a) the newsgroup is in the active file and */
/* (b) the directory name is the group name with all */
/* the"."s replaced with "/"s and all of that under the */
/* news directory. */
/* */
/* Names are insured to be valid by ImportNewsGroup, which maps */
/* invalid characters and truncates names as required. */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* RCS Information */
/*--------------------------------------------------------------------*/
/*
* $Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $
*
* $Log: RNEWS.C $
* Revision 1.9 1993/04/17 13:40:39 ahd
* fix compile errors for snews fix
*
* Revision 1.8 1993/04/17 13:23:37 ahd
* make snews option more compatible with snews (which is brain dead)
*
* Revision 1.7 1993/04/16 12:55:36 dmwatt
* Bounds check group lengths
*
* Revision 1.5 1993/04/11 00:33:54 ahd
* Global edits for year, TEXT, etc.
*
* Revision 1.4 1993/03/24 01:57:30 ahd
* Corrections for short articles
* Corrections for articles claimed to be zero length
* Resync gracefully after incorrect length descriptor
*
* Revision 1.3 1993/03/06 23:04:54 ahd
* Do not delete open files
*
* Revision 1.2 1992/11/22 21:14:21 ahd
* Reformat selected sections of code
* Check for premature end of articles in batched news
*
*/
static const char rcsid[] =
"$Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $";
/*--------------------------------------------------------------------*/
/* System include files */
/*--------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
/*--------------------------------------------------------------------*/
/* UUPC/extended include files */
/*--------------------------------------------------------------------*/
#include "lib.h"
#include "active.h"
#include "getopt.h"
#include "getseq.h"
#include "history.h"
#include "hlib.h"
#include "import.h"
#include "importng.h"
#include "logger.h"
#include "timestmp.h"
/*--------------------------------------------------------------------*/
/* Global defines */
/*--------------------------------------------------------------------*/
#define UNCOMPRESS "uncompre"
/*--------------------------------------------------------------------*/
/* Global variables */
/*--------------------------------------------------------------------*/
currentfile();
extern struct grp *group_list; /* List of all groups */
FILE *hfile = NULL; /* History file */
char history_date[12]; /* dd/mm/yyyy + null + 1 for no good reason */
char hbuff[BUFSIZ];
/*--------------------------------------------------------------------*/
/* Functions in this file */
/*--------------------------------------------------------------------*/
static boolean deliver_article(char *art_fname);
/* Distribute the article to the
proper newsgroups */
static void copy_file(FILE *f,
char *group,
char *xref); /* Copy file (f) to newsgroup */
static struct grp *find_newsgroup(const char *grp);
/* Get the grp struct for the newsgroup */
static void get_snum(const char *group, char *snum);
/* Get (and format) the next article
number in group */
static void fixEOF( char *buf, int bytes );
static int Single( char *filename , FILE *stream );
static int Compressed( char *filename , FILE *in_stream );
static int Batched( char *filename, FILE *stream);
static void xmit_news( char *sysname, FILE *in_stream );
static int copy_snews( char *filename, FILE *stream );
/*--------------------------------------------------------------------*/
/* m a i n */
/* */
/* Main program */
/* */
/* Exit conditions */
/* */
/* 0 - Success */
/* 1 - System configuration failed */
/* 2 - Unable to open working file */
/* 4 - out of memory */
/* 5 - Unable to create history dbm file */
/* 6 - Problem decompressing news batch */
/* 7 - Unable to create cmprssed directory */
/*--------------------------------------------------------------------*/
void main( int argc, char **argv)
{
struct tm *local_now;
long now = time(nil(long));
FILE *f;
char in_filename[FILENAME_MAX];
char filename[FILENAME_MAX];
int c;
int status;
#if defined(__CORE__)
copywrong = strdup(copyright);
checkref(copywrong);
#endif
banner( argv );
if (!configure( B_NEWS ))
exit(1); /* system configuration failed */
openlog( NULL ); /* Begin logging to disk */
if (argc > 1)
{
int option;
/*------------------------------------------------------------*/
/* parse arguments */
/*------------------------------------------------------------*/
while ((option = getopt(argc, argv, "f:x:")) != EOF)
{
switch (option)
{
case 'f':
strcpy(in_filename, optarg);
f = freopen(in_filename, "r", stdin);
if (f == NULL) {
printerr( in_filename );
panic();
} else
printmsg(2, "Opened %s as newsfile", in_filename);
break;
case 'x':
debuglevel = atoi(optarg);
break;
case '?':
puts("\nUsage:\trnews [-f newsfile] [-x debug]");
return;
} /* break */
} /* while */
} /* if (argc > 1) */
tzset(); /* Set up time zone information */
/*--------------------------------------------------------------------*/
/* If we are processing snews input, write it all out to the */
/* news directory as one file and return gracefully. */
/*--------------------------------------------------------------------*/
if ( bflag[F_SNEWS])
{
char *savetemp = E_tempdir; /* Save the real temp directory */
if (bflag[F_HISTORY])
{
printmsg(0,
"rnews: Conflicting options snews and history specified!");
panic();
} /* else if */
E_tempdir = E_newsdir; /* Generate this file in news */
mktempname(filename, "ART"); /* Get the file name */
E_tempdir = savetemp; /* Restore true directory name */
exit (copy_snews( filename, stdin ));
/* Dump news into NEWS directory */
}
else
mktempname(filename, "tmp"); /* Make normal temp name */
/*--------------------------------------------------------------------*/
/* Load the active file and validate its data */
/*--------------------------------------------------------------------*/
get_active(); /* Get sequence numbers for groups
from active file */
validate_newsgroups(); /* Make sure all directories exist */
/*--------------------------------------------------------------------*/
/* Initialize history processing */
/*--------------------------------------------------------------------*/
local_now = localtime(&now);
sprintf(history_date, "%2.2d/%2.2d/%4d", local_now->tm_mday,
local_now->tm_mon+1,
local_now->tm_year+1900);
/*--------------------------------------------------------------------*/
/* Open (or create) the history file */
/*--------------------------------------------------------------------*/
if ( bflag[F_HISTORY] )
{
if (history_exists())
hfile = open_history(history_date);
else
hfile = create_history(history_date);
} /* if */
/*--------------------------------------------------------------------*/
/* This loop copies the file to the NEWS directory. */
/* */
/* A news article/batch either has a '#' character as its first */
/* character or it does not. */
/* */
/* If it does not it is a single (unbatched, uncompressed) */
/* article. */
/* */
/* If the first character _is_ a '#', the first line is #! */
/* cunbatch\n which means that it is a compressed batch; it */
/* will be uncompressed and then re-fed to rnews or the first */
/* line can be #! rnews nnn\n (where nnn is some number) which */
/* means that the next nnn characters are an article and that */
/* more might follow. */
/* */
/* Due to a "feature" in the compressed batch, there may be */
/* _no_ articles batched (an article destined for transmittal */
/* is cancelled before being sent). */
/* */
/* Since this is a bit spread out, the various clauses of the */
/* if statement will be marked with boxed 1, 2, or 3 (and a */
/* brief explanation. */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* Compressed files need to be read in BINARY mode so that */
/* "magic" characters (like ^Z) don't upset it. Batched files */
/* need to be read in TEXT mode so that the character count is */
/* correct. The other case doesn't matter. */
/*--------------------------------------------------------------------*/
c = getc(stdin);
ungetc(c, stdin);
if (c != '#') {
/***********************************************/
/* 1 single (unbatched, uncompressed) article */
/***********************************************/
status = Single(filename, stdin);
}
else {
char buf[BUFSIZ];
int fields = fscanf(stdin, "#! %s ", &buf);
if ((fields == 1) && (strcmp(buf, "cunbatch") == 0))
{
/***********************************************/
/* 2 Compressed batch */
/***********************************************/
status = Compressed(filename, stdin);
}
else {
/***********************************************/
/* 3 Uncompressed batch */
/***********************************************/
status = Batched( filename, stdin );
} /* else */
} /* else */
/*--------------------------------------------------------------------*/
/* Close open files and exit */
/*--------------------------------------------------------------------*/
put_active();
if (hfile != NULL)
fclose(hfile);
exit(status);
} /*main*/
/*--------------------------------------------------------------------*/
/* S i n g l e */
/* */
/* Deliver a single article to the proper news group(s) */
/*--------------------------------------------------------------------*/
static int Single( char *filename , FILE *stream )
{
char tmp_fname[FILENAME_MAX];
FILE *tmpf;
char buf[BUFSIZ];
unsigned chars_read;
unsigned chars_written;
/*--------------------------------------------------------------------*/
/* Make a file name and then open the file to write the article into */
/*--------------------------------------------------------------------*/
tmpf = FOPEN(filename, "w", BINARY_MODE);
if ( tmpf == NULL )
{
printerr( tmp_fname );
panic();
}
/*--------------------------------------------------------------------*/
/* Now copy the input into our holding bin */
/*--------------------------------------------------------------------*/
while ((chars_read = fread(buf,sizeof(char), BUFSIZ, stream)) != 0)
{
chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
if (chars_written != chars_read)
{
printerr( filename );
printmsg(0, "rnews: Error writing single article to working file");
fclose( tmpf );
unlink( filename );
panic();
}
}
/*--------------------------------------------------------------------*/
/* Close the file, deliver the article, and return the caller */
/*--------------------------------------------------------------------*/
fclose(tmpf);
deliver_article(filename);
unlink( filename );
return 0;
} /* Single */
/*--------------------------------------------------------------------*/
/* C o m p r e s s e d */
/* */
/* Decompress news */
/*--------------------------------------------------------------------*/
static int Compressed( char *filename , FILE *in_stream )
{
FILE *work_stream;
char zfile[FILENAME_MAX];
char unzfile[FILENAME_MAX];
char buf[BUFSIZ];
boolean first_time = TRUE;
char *program, *args;
long cfile_size = 0L;
size_t chars_read, i;
int status = 0;
boolean needtemp = TRUE;
char *sysname; /* For reading systems to process */
/*--------------------------------------------------------------------*/
/* Copy the compressed file to the "holding" directory */
/*--------------------------------------------------------------------*/
setmode(fileno(in_stream), O_BINARY);/* Don't die on control-Z, etc */
fseek(in_stream, 0L, SEEK_SET); /* Back to the beginning */
while( needtemp )
{
mktempname( zfile , "Z" ); /* Generate "compressed" file
name */
strcpy( unzfile, zfile );
unzfile[ strlen(unzfile)-2 ] = '\0';
if ( access( unzfile, 0 )) /* Does the host file exist? */
needtemp = FALSE; /* No, we have a good pair */
else
printmsg(0,"Had compressed name %s, found %s already exists!",
zfile, unzfile );
} /* while */
/*--------------------------------------------------------------------*/
/* Open the file, with error recovery */
/*--------------------------------------------------------------------*/
if ((work_stream = FOPEN(zfile, "w", BINARY_MODE)) == nil(FILE))
{
printmsg(0, "Compressed: Can't open %s (%d)", zfile, errno);
printerr(zfile);
return 2;
}
printmsg(2, "Compressed: Copy to %s for later processing", zfile);
/*--------------------------------------------------------------------*/
/* Main loop to copy compressed file */
/*--------------------------------------------------------------------*/
while ((chars_read = fread(buf,sizeof(char), BUFSIZ, in_stream)) != 0)
{
char *t_buf = buf;
if (first_time)
{
t_buf += sizeof("#! cunbatch");
first_time = FALSE;
chars_read -= (t_buf - buf);
while ((*t_buf == ' ') || (*t_buf == '\n') || (*t_buf == '\r'))
{
t_buf++;
chars_read--;
} /* while */
} /* if */
i = fwrite(t_buf,sizeof(char),chars_read,work_stream);
if (i != chars_read)
{
fclose( work_stream );
printerr( zfile );
panic();
}
cfile_size += (long)chars_read;
} /* while */
fclose(work_stream);
/*--------------------------------------------------------------------*/
/* If the file is empty, delete it gracefully */
/*--------------------------------------------------------------------*/
if (cfile_size == 3)
{
unlink(zfile); /* Get rid of null file */
printmsg(1, "Compressed: %s empty, deleted", zfile);
return status;
}
else
printmsg(2,"Compressed: Copy to %s complete, %ld characters",
zfile, cfile_size);
/*--------------------------------------------------------------------*/
/* Special hack for creating mirror images of the news feed */
/*--------------------------------------------------------------------*/
sysname = getenv( "UUPCSHADOWS" );
if ( sysname != NULL )
{
strcpy( buf, sysname);
sysname = strtok( buf, WHITESPACE );
while( sysname != NULL )
{
printmsg(1,"Compressed: Shadowing news to %s", sysname );
fseek(in_stream, 0L, SEEK_SET); /* Back to the beginning */
xmit_news( sysname, in_stream );
sysname = strtok( NULL, WHITESPACE );
}
} /* if */
/*--------------------------------------------------------------------*/
/* Uncompress the article and feed it back to rnews */
/*--------------------------------------------------------------------*/
if ( E_uncompress == NULL )
{
program = UNCOMPRESS;
args = zfile;
printmsg(2,"Compressed: %s %s", program , args);
}
else {
sprintf( buf, E_uncompress, zfile, unzfile );
printmsg(2,"Compressed: %s", buf );
program = strtok( buf, WHITESPACE );
args = strtok( NULL, "");
if ( args != NULL )
while (isspace(*args))
args++;
}
status = spawnlp(P_WAIT, program, program, args, NULL);
unlink( zfile ); /* Kill the compressed input file */
if (status != 0)
{
if (status == -1)
{
printmsg( 0, "Compress: spawn failed completely" );
printerr( program );
}
else
printmsg(0, "%s command failed (exit code %d)",
UNCOMPRESS, status);
panic();
} /* if status != 0 */
/*--------------------------------------------------------------------*/
/* Now process the file as normal batched news */
/*--------------------------------------------------------------------*/
/* Create uncompressed output file name */
work_stream = FOPEN( unzfile, "r", BINARY_MODE);
if ( work_stream == NULL )
{
printerr( unzfile );
panic();
}
status = Batched( filename, work_stream );
/*--------------------------------------------------------------------*/
/* Clean up and return to caller */
/*--------------------------------------------------------------------*/
fclose( work_stream );
unlink( unzfile );
return status;
} /* Compressed */
/*--------------------------------------------------------------------*/
/* B a t c h e d */
/* */
/* Handle batched, uncompressed news */
/*--------------------------------------------------------------------*/
static int Batched( char *filename, FILE *stream)
{
char buf[BUFSIZ * 2];
int status = 0;
long article_size;
int articles = 0;
int ignored = 0;
boolean gotsize = FALSE;
int chars_read;
int chars_written;
/*--------------------------------------------------------------------*/
/* This is an uncompressed batch. Copy it to the working */
/* directory and then distribute the individual articles. */
/*--------------------------------------------------------------------*/
setmode(fileno(stream), O_BINARY ); /* Don't die on Cntrl Z, etc. */
fseek(stream, 0L, SEEK_SET); /* Back to the beginning */
while( ! feof( stream ) && ! ferror( stream ))
{
long article_left;
int max_read = (long) sizeof buf;
long skipped_lines = 0;
long skipped_bytes = 0;
FILE *tmpf;
/*--------------------------------------------------------------------*/
/* Handle next article (articles are separated by the line */
/* indicating their size when they are batched.) */
/*--------------------------------------------------------------------*/
while ( ! gotsize )
{
if (fgets( buf, sizeof buf, stream ) == NULL)
break;
if ( equaln( "#! rnews", buf, 8) )
{
article_size = 0;
sscanf(buf, "#! rnews %ld \n", &article_size);
gotsize = TRUE;
}
else {
skipped_lines ++;
skipped_bytes += strlen( buf );
}
} /* while */
if ( skipped_lines )
printmsg(0,
"Batched: Skipped %ld bytes in %ld "
"lines after article %d",
skipped_bytes,
skipped_lines,
articles );
/*--------------------------------------------------------------------*/
/* Trap end of file */
/*--------------------------------------------------------------------*/
if ( ! gotsize )
{
if ( ferror( stream ))
printerr( "stdin" );
break;
}
article_left = article_size;
gotsize = FALSE;
/*--------------------------------------------------------------------*/
/* Open up our next working file */
/*--------------------------------------------------------------------*/
tmpf = FOPEN(filename, "w", BINARY_MODE);
if ( tmpf == NULL )
{
printerr( filename );
panic();
}
/*--------------------------------------------------------------------*/
/* Copy this article to the temp file (except for the last block) */
/*--------------------------------------------------------------------*/
if ( article_size )
{
do {
if ( article_left < max_read )
max_read = (int) article_left;
chars_read = fread(buf, sizeof(char), max_read, stream);
if ( (chars_read < max_read) && ferror( stream ))
{
printerr("STDIN");
panic();
}
if ( chars_read == 0)
break;
fixEOF( buf , chars_read );
chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
if (chars_read != chars_written)
{
printmsg(0,"Batched: Read %d bytes, only wrote %d bytes of article %d",
chars_read, chars_written , articles + 1);
printerr(filename);
}
article_left -= chars_read;
} while (article_left > 0);
if ( article_left ) // Premature EOF?
printmsg(0,"Batched: Unexpected EOF for article %d, "
"read %ld bytes of expected %ld",
articles + 1,
article_size - article_left, article_size );
} /* if */
else {
long actual_size = 0;
do {
if (fgets( buf, sizeof buf, stream ) == NULL)
{
if ( ferror( stream ))
printerr( filename );
break;
}
chars_read = strlen( buf );
if ( equaln( "#! rnews", buf, 8) )
{
sscanf(buf, "#! rnews %ld \n", &article_size);
gotsize = TRUE;
}
else if ( chars_read > 0 )
{
actual_size += chars_read;
chars_written = fwrite(buf,
sizeof(char),
chars_read,
tmpf);
if (chars_read != chars_written)
{
printmsg(0,
"Batched: Read %d bytes, only wrote %d bytes of article %d",
chars_read, chars_written , articles + 1);
printerr(filename);
}
} /* else */
} while( ! gotsize );
printmsg(2,"Batched: Article %d size %ld",
articles + 1,
actual_size );
} /* else */
/*--------------------------------------------------------------------*/
/* Close the file, deliver its contents, and get rid of it */
/*--------------------------------------------------------------------*/
fclose(tmpf);
if ( ! deliver_article(filename) )
ignored ++;
unlink( filename );
articles ++;
} /* while */
/*--------------------------------------------------------------------*/
/* Return to caller */
/*--------------------------------------------------------------------*/
if ( ignored )
printmsg(1,"Batched: Unbatched %d articles (discarded %d of these)",
articles , ignored);
else
printmsg(1,"Batched: Unbatched %d articles", articles );
return status;
} /* Batched */
/*--------------------------------------------------------------------*/
/* f i x E O F */
/* */
/* Zap Cntrl-Z characters in the input stream */
/*--------------------------------------------------------------------*/
static void fixEOF( char *buf, int bytes )
{
static warn = TRUE;
while ( bytes-- )
{
if ( *buf == ('Z' - 'A'))
{
*buf = 'Z';
if ( warn )
{
printmsg(0,"Altered Cntl-Z to Z");
warn = FALSE;
} /* if */
} /* if */
} /* while */
} /* fixEOF */
/*--------------------------------------------------------------------*/
/* d e l i v e r _ a r t i c l e */
/* */
/* Determine delivery of a posting */
/*--------------------------------------------------------------------*/
static boolean deliver_article(char *art_fname)
{
char groupy[MAXGRP];
char *newsgroups = NULL; /* The Newsgroups: line */
char *messageID = NULL; /* The Message-ID: line */
char *gc_ptr; /* Scratch pointers. Mostly used to go */
char *gc_ptr1; /* down the list of newsgroups. */
FILE *tfile; /* The article file */
int n_hdrs; /* Number of desired headers seen */
int b_xref;
int line_len;
char hist_record[BUFSIZ]; /* buffer for history file
(also used for article) */
char groups[BUFSIZ];
char message_buf[BUFSIZ];
char snum[10];
tfile = FOPEN(art_fname, "r", BINARY_MODE);
if ( tfile == NULL )
{
printerr( art_fname );
panic();
}
/*--------------------------------------------------------------------*/
/* Get fields necessary for distribution (Newsgroups:) and the */
/* history file (Message-ID:). Also, if the article is going */
/* to more than one newsgroup, flag the creation of Xref: fields. */
/*--------------------------------------------------------------------*/
n_hdrs = b_xref = 0;
while (n_hdrs < 2)
{
/* Get the next line */
gc_ptr = fgets(hist_record, sizeof(hist_record), tfile);
/*--------------------------------------------------------------------*/
/* Check for end of the headers */
/*--------------------------------------------------------------------*/
if ((gc_ptr == NULL) || (strlen(hist_record) == 1))
{
/* Ooops. Missing Message-ID: or Newsgroups: */
if (messageID == NULL)
printmsg(0, "Article has no Message-ID:, discarded");
else {
if (newsgroups == NULL)
{
printmsg(0,
"Article %s has no Newsgroups: line, discarded",
messageID);
} /* if */
else
break;
} /* else */
fclose(tfile);
return FALSE;
} /* if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) */
line_len = strlen(hist_record);
if (hist_record[line_len-1] == '\n')
hist_record[(line_len--)-1] = '\0';
if (hist_record[line_len-1] == '\r')
hist_record[(line_len--)-1] = '\0';
if (equalni(hist_record, "Newsgroups:", strlen("Newsgroups:")))
{
/* Handle Newsgroups: line*/
if (newsgroups == NULL)
{
gc_ptr += strlen("Newsgroups:") + 1;
newsgroups = strcpy(groups, gc_ptr);
newsgroups[strlen(newsgroups)+1] = '\0'; /* Guard char for rescan */
n_hdrs++;
b_xref = (strchr(newsgroups, ',') != NULL); /* more than 1 group */
} /* i.e. do we need to create a Xrefs: line ? */
else
printmsg(0, "Article has multiple Newsgroups: lines");
}
else if (equalni(hist_record, "Message-ID:", strlen("Message-ID:")))
{
/* Handle Message-ID: line */
if (messageID == NULL)
{
gc_ptr += strlen("Message-ID:") + 1;
messageID = message_buf;
messageID[0] = '\0';
if (*gc_ptr != '<') strcat(messageID, "<");
strcat(messageID, gc_ptr);
if (messageID[strlen(messageID)-1] != '>')
strcat(messageID,">");
n_hdrs++;
} /* if (messageID == NULL) */
}
} /* while getting Newsgroups: and Message-ID: */
/*--------------------------------------------------------------------*/
/* Check whether article has been received before */
/*--------------------------------------------------------------------*/
if ( bflag[ F_HISTORY ] )
{
if (is_in_history(hfile, messageID))
{
printmsg(2, "rnews: Duplicate article %s", messageID);
fclose(tfile);
return FALSE;
}
/* Start building the history record for this article */
strcpy(hist_record, messageID);
strcat(hist_record, " ");
strcat(hist_record, history_date);
strcat(hist_record, " ");
gc_ptr1 = newsgroups;
while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) {
gc_ptr[0] = '\0';
if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
gc_ptr1 = gc_ptr + 1;
continue; /* Punt the newsgroup history record */
}
strcpy(groupy, gc_ptr1);
strcat(hist_record, groupy);
strcat(hist_record, ":");
gc_ptr1 = gc_ptr + 1;
get_snum(groupy,snum);
strcat(hist_record, snum);
strcat(hist_record, ",");
}
strcpy(groupy, gc_ptr1);
strcat(hist_record, groupy);
strcat(hist_record, ":");
get_snum(groupy,snum);
strcat(hist_record, snum);
strcat(hist_record, "\n");
/* Restore the newsgroups line */
while (newsgroups[strlen(newsgroups)+1] != '\0') {
newsgroups[strlen(newsgroups)] = ',';
}
/* Post the history record */
fseek(hfile, 0L, SEEK_END);
fwrite(hist_record, sizeof(char), strlen(hist_record), hfile);
} /* if ( bflag[ F_HISTORY ] ) */
/*--------------------------------------------------------------------*/
/* Now build the Xref: line (if we need to) */
/*--------------------------------------------------------------------*/
if (b_xref) {
strcpy(hist_record, "Xref: ");
strcat(hist_record, E_nodename);
strcat(hist_record, " ");
gc_ptr1 = newsgroups;
while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
{
gc_ptr[0] = '\0';
if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
gc_ptr1 = gc_ptr + 1;
continue; /* Punt the newsgroup history record */
}
strcpy(groupy, gc_ptr1);
strcat(hist_record, groupy);
strcat(hist_record, ":");
gc_ptr1 = gc_ptr + 1;
get_snum(groupy,snum);
strcat(hist_record, snum);
strcat(hist_record, " ");
}
strcpy(groupy, gc_ptr1);
strcat(hist_record, groupy);
strcat(hist_record, ":");
get_snum(groupy,snum);
strcat(hist_record, snum);
strcat(hist_record, "\n");
/* Restore the newsgroups line */
while (newsgroups[strlen(newsgroups)+1] != '\0') {
newsgroups[strlen(newsgroups)] = ',';
}
}
/*--------------------------------------------------------------------*/
/* We now need to copy the file to each group in groupys */
/*--------------------------------------------------------------------*/
gc_ptr1 = newsgroups;
while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
{
gc_ptr[0] = '\0';
strcpy(groupy, gc_ptr1);
gc_ptr1 = gc_ptr + 1;
copy_file(tfile, groupy, b_xref ? hist_record : NULL);
}
strcpy(groupy, gc_ptr1);
copy_file(tfile, groupy, b_xref ? hist_record : NULL);
fclose(tfile);
return TRUE;
} /* deliver_article */
/*--------------------------------------------------------------------*/
/* f i n d _ n e w s g r o u p */
/* */
/* Locate a news group in our list */
/*--------------------------------------------------------------------*/
static struct grp *find_newsgroup(const char *grp)
{
struct grp *cur = group_list;
while ((strcmp(grp,cur->grp_name) != 0)) {
if (cur->grp_next != NULL) {
cur = cur->grp_next;
} else {
return NULL;
}
}
return cur;
}
/*--------------------------------------------------------------------*/
/* c o p y _ f i l e */
/* */
/* Write an article to it's final resting place */
/*--------------------------------------------------------------------*/
static void copy_file(FILE *input,
char *group,
char *xref)
{
struct grp *cur;
char filename[FILENAME_MAX];
char buf[BUFSIZ];
FILE *output;
/*--------------------------------------------------------------------*/
/* Determine if the news has been already posted */
/*--------------------------------------------------------------------*/
cur = find_newsgroup(group);
if (cur == NULL)
{
printmsg(3, "rnews: Article cross-posted to %s", group);
return;
}
/*--------------------------------------------------------------------*/
/* Now build a file name */
/*--------------------------------------------------------------------*/
ImportNewsGroup( filename, cur->grp_name, cur->grp_high++);
/*--------------------------------------------------------------------*/
/* We have a file name, open the file */
/*--------------------------------------------------------------------*/
printmsg(2, "rnews: Saving %s article in %s",
cur->grp_name, filename);
if ((output = FOPEN(filename, "w",TEXT_MODE)) == nil(FILE))
{
printerr( filename );
printmsg(0, "rnews: Unable to save article");
return;
}
rewind(input);
if (xref) /* write new Xref: line first */
{
if (fputs(xref, output) == EOF)
{
printerr( filename );
panic();
}
}
while (fgets(buf, sizeof buf, input) != NULL)
{
if (equalni(buf, "Path:", strlen("Path:")))
{
fprintf(output, "Path: %s!%s", E_nodename,
buf + strlen("Path:") + 1);
continue;
}
else if (equalni(buf, "Xref:", strlen("Xref:")))
continue; /* skip possibly old Xref: line */
if (fputs(buf, output) == EOF)
{
printerr( filename );
panic();
}
} /* while */
fclose(output);
} /* copy_file */
/*--------------------------------------------------------------------*/
/* g e t _ s n u m */
/* */
/* Get highest article number of newsgroup */
/*--------------------------------------------------------------------*/
static void get_snum(const char *group, char *snum)
{
struct grp *cur;
strcpy(snum, "0");
cur = find_newsgroup(group);
if (cur == NULL)
return;
sprintf(snum, "%d", cur->grp_high);
} /* snum */
/*--------------------------------------------------------------------*/
/* x m i t _ n e w s */
/* */
/* A cruel hack to transmit news to other systems */
/*--------------------------------------------------------------------*/
static void xmit_news( char *sysname, FILE *in_stream )
{
static char *spool_fmt = SPOOLFMT; /* spool file name */
static char *dataf_fmt = DATAFFMT;
static char *send_cmd = "S %s %s %s - %s 0666\n";
static long seqno = 0;
FILE *out_stream; /* For writing out data */
char buf[BUFSIZ];
unsigned len;
char msfile[FILENAME_MAX]; /* MS-DOS format name of files */
char msname[22]; /* MS-DOS format w/o path name */
char tmfile[15]; /* Call file, UNIX format name */
char ixfile[15]; /* eXecute file for remote system,
UNIX format name for local system */
char idfile[15]; /* Data file, UNIX format name */
char rdfile[15]; /* Data file name on remote system,
UNIX format */
char rxfile[15]; /* Remote system UNIX name of eXecute
file */
char *seq;
/*--------------------------------------------------------------------*/
/* Create the UNIX format of the file names we need */
/*--------------------------------------------------------------------*/
seqno = getseq();
seq = JobNumber( seqno );
sprintf(tmfile, spool_fmt, 'C', sysname, 'd' , seq);
sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
/*--------------------------------------------------------------------*/
/* create remote X (xqt) file */
/*--------------------------------------------------------------------*/
importpath( msname, ixfile, sysname);
mkfilename( msfile, E_spooldir, msname);
out_stream = FOPEN(msfile, "w", BINARY_MODE);
if ( out_stream == NULL )
{
printmsg(0, "xmit_news: cannot open X file %s", msfile);
printerr(msfile);
return ;
} /* if */
if (setvbuf( out_stream, NULL, _IONBF, 0))
{
printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
ixfile, msfile);
printerr(msfile);
panic();
} /* if */
fprintf(out_stream, "R %s %s\nU %s %s\nF %s\nI %s\nC rnews\n",
"uucp", E_domain,
"uucp", E_nodename,
rdfile, rdfile);
fclose(out_stream);
/*--------------------------------------------------------------------*/
/* Create the data file with the mail to send to the remote system */
/*--------------------------------------------------------------------*/
importpath(msname, idfile, sysname);
mkfilename( msfile, E_spooldir, msname);
out_stream = FOPEN(msfile, "w", BINARY_MODE);
if (out_stream == NULL )
{
printerr(msfile);
printmsg(0,
"xmit_news: Cannot open spool file \"%s\" for output",
msfile);
return;
}
if (setvbuf( out_stream, NULL, _IONBF, 0))
{
printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
idfile, msfile);
printerr(msfile);
panic();
} /* if */
/*--------------------------------------------------------------------*/
/* Loop to copy the data */
/*--------------------------------------------------------------------*/
while ( (len = fread( buf, 1, sizeof buf, in_stream)) != 0)
{
if (fwrite( buf, 1, len, out_stream ) != len) /* I/O error? */
{
printerr(msfile);
fclose(out_stream);
return;
} /* if */
} /* while */
fclose( out_stream );
/*--------------------------------------------------------------------*/
/* create local C (call) file */
/*--------------------------------------------------------------------*/
importpath( msname, tmfile, sysname);
mkfilename( msfile, E_spooldir, msname);
out_stream = FOPEN(msfile, "w",TEXT_MODE);
if (out_stream == NULL)
{
printerr( msname );
printmsg(0, "xmit_news: cannot open C file %s", msfile);
return;
}
fprintf(out_stream, send_cmd, idfile, rdfile,
"uucp", idfile);
fprintf(out_stream, send_cmd, ixfile, rxfile,
"uucp", ixfile);
fclose(out_stream);
} /* xmit_news */
/*--------------------------------------------------------------------*/
/* c o p y _ s n e w s */
/* */
/* Process news destined for the simple news reader */
/*--------------------------------------------------------------------*/
static int copy_snews( char *filename, FILE *stream )
{
char buf[BUFSIZ];
size_t len;
FILE *out_stream = FOPEN(filename, "w", BINARY_MODE);
if ( out_stream == NULL )
{
printerr(filename);
panic();
} /* if */
if (setvbuf( out_stream, NULL, _IONBF, 0))
{
printmsg(0, "copy_snews: Cannot unbuffer file %s.", filename);
printerr(filename);
panic();
} /* if */
/*--------------------------------------------------------------------*/
/* Perform the copy */
/*--------------------------------------------------------------------*/
while ( (len = fread( buf, 1, sizeof buf, stream)) != 0)
{
if (fwrite( buf, 1, len, out_stream ) != len) /* I/O error? */
{
printerr(filename);
panic();
} /* if */
} /* while */
/*--------------------------------------------------------------------*/
/* Close the file */
/*--------------------------------------------------------------------*/
fclose( out_stream );
fclose( stream );
return 0;
} /* copy_snews */